/*===========================================================================
 * Include file
 *===========================================================================*/ 

#include "includes_fw.h"
#include "lib_retina.h"
#include "motion_dtc.h"
#include "mmpf_mp4venc.h"
#include "mmpf_h264enc.h"

#if (SUPPORT_H264MV_MD)

/*===========================================================================
 * Global varible
 *===========================================================================*/ 

static MOTION_DETECT_CONFIG m_MDConfig = {
    40, //mvWidth	: width/16
    23, //mvHeight	: height/16
    96,  //ulMvXTh	: threshold of movement to be regarded as motion
    48,  //ulMvYTh	: threshold of movement to be regarded as motion
    10,  //ulCntTh	: threshold of MB counts with movement larger than range_th
    511, //mvX_max	: the max movement range (-mv_max ~ mv_max)
    255  //mvY_max	: the max movement range (-mv_max ~ mv_max)
};

static MMP_BOOL     gbMDAreaMask[30][40];
static MMP_USHORT   gsMDAreaMaskCount = 0;
static MMP_SHORT    gsMDSensitivity = 50;

/*===========================================================================
 * Main body
 *===========================================================================*/ 

void MD_Initialize(int mvWidth, int mvHeight, int mvX_max, int mvY_max)
{
    m_MDConfig.mvWidth  = mvWidth; 
    m_MDConfig.mvHeight = mvHeight;
    m_MDConfig.mvX_max   = mvX_max;
    m_MDConfig.mvY_max   = mvY_max;
    dbg_printf(3, "W = %d, H = %d, Xm = x%X, Ym = x%X\r\n", m_MDConfig.mvWidth, m_MDConfig.mvHeight, m_MDConfig.mvX_max, m_MDConfig.mvY_max);
}

void MD_GetMBRngBd(MMP_USHORT *usWidth, MMP_USHORT *usHeight)
{
    *usWidth = m_MDConfig.mvWidth;
    *usHeight = m_MDConfig.mvHeight;
}

MMP_USHORT MD_GetMDAreaMaskCount(void)
{
    return gsMDAreaMaskCount;
}

void MD_SetMDThCntBySensitivity(MMP_USHORT usSenRange)
{
    int CntTh;
    
    CntTh = (int)((gsMDAreaMaskCount * 2) / (usSenRange + 4));
    MD_SetCntTh(CntTh);
}

void MD_SetMvThBySensitivity(MMP_USHORT usSenRange)
{
    MMP_UBYTE ratio;
    int MvXTh, MvYTh;
    
    ratio = (MMP_UBYTE)(usSenRange / 20);
    switch(ratio){
    case 0:
        MvXTh = (int)((m_MDConfig.mvX_max * 25) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 25) / 100);
        break;
    case 1:
        MvXTh = (int)((m_MDConfig.mvX_max * 20) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 20) / 100);
        break;
    case 2:
        MvXTh = (int)((m_MDConfig.mvX_max * 15) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 15) / 100);
        break;
    case 3:
        MvXTh = (int)((m_MDConfig.mvX_max * 10) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 10) / 100);
        break;
    case 4:
        MvXTh = (int)((m_MDConfig.mvX_max * 5) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 5) / 100);
        break;
    case 5:
    default:
        MvXTh = (int)((m_MDConfig.mvX_max * 1) / 100);
        MvYTh = (int)((m_MDConfig.mvY_max * 1) / 100);
        break;
    }

    MD_SetMvThreshold(MvXTh, MvYTh);
}

MMP_USHORT MD_GetMDSensitivity(void)
{
    return gsMDSensitivity;
}

void MD_SetMDSensitivity(MMP_USHORT usRange)
{
    gsMDSensitivity = (((usRange) > (100)) ? (100) : (usRange));
    
    MD_SetMDThCntBySensitivity(gsMDSensitivity);
    MD_SetMvThBySensitivity(gsMDSensitivity);
}

void MD_SetAreaMask(MMP_USHORT usMbX, MMP_USHORT usMbY, MMP_BOOL bEnable)
{
    MMP_USHORT x, y;

    x = (((usMbX) > (m_MDConfig.mvWidth - 1)) ? (m_MDConfig.mvWidth - 1) : (usMbX));
    y = (((usMbY) > (m_MDConfig.mvHeight - 1)) ? (m_MDConfig.mvHeight - 1) : (usMbY));
    gbMDAreaMask[y][x] = bEnable;
    //dbg_printf(3, "Mask[%d][%d]\r\n", y, x);
}

void MD_SetAllAreaMask(MMP_BOOL bEnable)
{
    MMP_USHORT i, j;
    
    for(j = 0 ; j < m_MDConfig.mvHeight ; j++){
        for(i = 0 ; i < m_MDConfig.mvWidth ; i++){
            gbMDAreaMask[j][i] = bEnable;
        }
    }
    if(bEnable)
        gsMDAreaMaskCount = (MMP_USHORT)(m_MDConfig.mvWidth * m_MDConfig.mvHeight); 
    else
        gsMDAreaMaskCount = 0;
        
    MD_SetMDThCntBySensitivity(gsMDSensitivity);
}

void MD_SetMvThreshold(int ulMvXTh, int ulMvYTh)
{
    m_MDConfig.ulMvXTh = (((ulMvXTh) > (m_MDConfig.mvX_max)) ? (m_MDConfig.mvX_max) : (ulMvXTh));
    m_MDConfig.ulMvYTh = (((ulMvYTh) > (m_MDConfig.mvY_max)) ? (m_MDConfig.mvY_max) : (ulMvYTh));

    dbg_printf(3, "Xt = %d, Yt = %d\r\n", m_MDConfig.ulMvXTh, m_MDConfig.ulMvYTh);
}

void MD_GetMvThreshold(int *ulMvXTh, int *ulMvYTh)
{
    *ulMvXTh = m_MDConfig.ulMvXTh;
    *ulMvYTh = m_MDConfig.ulMvYTh;
}

void MD_SetCntTh(int ulCntTh)
{
    m_MDConfig.ulCntTh = (((ulCntTh) > (m_MDConfig.mvWidth*m_MDConfig.mvHeight)) ? (m_MDConfig.mvWidth*m_MDConfig.mvHeight) : (ulCntTh));

    dbg_printf(3, "CntTh = %d\r\n", m_MDConfig.ulCntTh);
}

void MD_GetCntTh(int *ulCntTh)
{
    *ulCntTh = m_MDConfig.ulCntTh;
}

int glMDMotionCnt;
MD_RESULT MD_Execute(MMP_BOOL isIFrame)
{
    int i, j, cnt_motion, tmpMvXTh, tmpMvYTh, tmpCntTh;
    MMPF_H264ENC_ENC_INFO *pEnc = MMPF_H264ENC_GetHandle(1);
    MMPF_H264ENC_TARGET_MB_INFO TargetMbMvInfo;
    MMP_H264ENC_BLK_MV *BlkMv = &(TargetMbMvInfo.BlkMv);
    MMP_USHORT usBlkIdx = 0, AreaMaskCnt;

    cnt_motion = 0;
    AreaMaskCnt = 0;

	tmpMvXTh  = m_MDConfig.ulMvXTh;
	tmpMvYTh  = m_MDConfig.ulMvYTh;
	tmpCntTh = m_MDConfig.ulCntTh;

    if (!isIFrame) {
	    //dbg_printf(3, "[%d]", usBlkIdx);
        for (j = 0; j < m_MDConfig.mvHeight; j++) {
            for (i = 0; i < m_MDConfig.mvWidth; i++){
                if(gbMDAreaMask[j][i] == TRUE){
                    MMPF_H264ENC_GetTargetMbMv(pEnc, usBlkIdx, BlkMv, &(TargetMbMvInfo.MbMode));
                    if ((abs(BlkMv->MvX) > tmpMvXTh) || (abs(BlkMv->MvY) > tmpMvYTh)) {	                
                        cnt_motion++;	              		
                    }
                    AreaMaskCnt++;
                }
                usBlkIdx++;
        #if 0
                if(((j%4) == 0) && ((i%8) == 0)){ 
                    dbg_printf(3, "(x%04X,x%04X) ", abs(BlkMv->MvX), abs(BlkMv->MvY)); 
                    if(i >= (m_MDConfig.mvWidth - 8))
                        dbg_printf(3, "\r\n[%03d]", usBlkIdx);
                }
        #endif    	
            }
        }
        if(AreaMaskCnt != gsMDAreaMaskCount){
            gsMDAreaMaskCount = AreaMaskCnt;
            MD_SetMDThCntBySensitivity(gsMDSensitivity);
        }
    }

    #if 0
        dbg_printf(3, "cnt_motion = %d\r\n", cnt_motion); 
    #endif
    #if 1
        glMDMotionCnt = cnt_motion;
    #endif    	
    if (cnt_motion > tmpCntTh)
        return MOTION_DETECT;
    else 
        return MOTION_NO;
}

#endif
